package com.kun.companion.core.context;

import cn.hutool.core.collection.CollUtil;
import com.kun.companion.core.AbstractApplication;
import com.kun.companion.core.context.factory.SingletonContextFactory;
import com.kun.companion.core.context.impl.BeanContext;
import com.kun.companion.core.exception.Assert;
import com.kun.companion.core.exception.BizException;
import com.kun.companion.core.util.NewClassGraphUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * 单例上下文工厂容器服务
 * <p>
 * 实现单例工厂的加载、依赖管理和生命周期控制，通过order值控制初始化顺序
 * </p>
 *
 * @author gzc
 * @since 2025/2/1
 **/
@SuppressWarnings("rawtypes")
public class ContextService {
    private static final Logger log = LoggerFactory.getLogger(ContextService.class);
    /**
     * 使用线程安全的ConcurrentHashMap存储工厂实例
     */
    private static final Map<Class<? extends SingletonContextFactory>, SingletonContextFactory> MAP = new ConcurrentHashMap<>(8);
    /**
     * 是否已经加载并初始化所有单例上下文工厂
     */
    private static volatile boolean isLoaded;

    /**
     * 加载并初始化所有单例上下文工厂
     *
     * @param packagePathList 需要扫描的包路径列表
     * @param cls             应用入口类（用于上下文传递）
     * @param args            命令行参数
     * @param loadUrlFunction URL加载策略函数
     * @throws BizException 当重复初始化时抛出
     */
    @SuppressWarnings("unchecked")
    public synchronized static void load(List<String> packagePathList,
                                         Class<? extends AbstractApplication> cls,
                                         String[] args,
                                         Function<String, URL> loadUrlFunction) {
        if (isLoaded) {
            Assert.throwBizException("容器服务已完成初始化加载，不可重复加载");
        }
        if (CollUtil.isEmpty(packagePathList)) {
            isLoaded = true;
            log.warn("空包路径列表，跳过上下文工厂加载");
            return;
        }

        // 包路径去重并转换为数组
        String[] distinctPackages = packagePathList.stream()
                .distinct()
                .toArray(String[]::new);

        // 扫描实现SingletonContextFactory的类
        List<String> factoryClasses = NewClassGraphUtil.findImplement(
                SingletonContextFactory.class,
                distinctPackages
        );

        if (CollUtil.isEmpty(factoryClasses)) {
            isLoaded = true;
            log.info("未扫描到有效的上下文工厂实现");
            return;
        }

        // 创建工厂实例并按order排序
        List<SingletonContextFactory> factories = createSortedFactories(factoryClasses);
        if (CollUtil.isEmpty(factories)) {
            isLoaded = true;
            log.error("上下文工厂实例化失败，无有效实例");
            return;
        }

        // 按顺序初始化工厂
        for (SingletonContextFactory factory : factories) {
            log.debug("正在初始化工厂: {}", factory.getClass().getName());
            factory.init(packagePathList, cls, loadUrlFunction);
            MAP.put(factory.getClass(), factory);
        }
        isLoaded = true;
        log.info("上下文容器加载完成，共初始化{}个工厂", MAP.size());
    }

    /**
     * 创建排序后的工厂实例列表
     *
     * @param classPaths 类全限定名列表
     * @return 按order值升序排列的工厂实例列表（过滤无效实例）
     */
    private static List<SingletonContextFactory> createSortedFactories(List<String> classPaths) {
        return classPaths.stream()
                .map(ContextService::instantiateFactory)
                .filter(Objects::nonNull)
                .sorted(Comparator.comparingInt(SingletonContextFactory::order))
                .toList();
    }

    /**
     * 实例化工厂类
     *
     * @param contextClassPath 类的全限定名
     * @return 成功实例化的工厂对象，失败返回null并记录日志
     */
    private static SingletonContextFactory instantiateFactory(String contextClassPath) {
        try {
            Object instance = NewClassGraphUtil.newInstance(contextClassPath);
            if (instance instanceof SingletonContextFactory factory) {
                return factory;
            }
            log.warn("类[{}]不是有效的SingletonContextFactory实现", contextClassPath);
        } catch (Exception e) {
            log.error("工厂类[{}]实例化失败: {}", contextClassPath, e.getMessage());
        }
        return null;
    }

    /**
     * 获取指定类型的上下文工厂服务
     *
     * @param cls 工厂类的类型
     * @param <T> 工厂类型泛型
     * @return 对应的工厂实例，未找到返回null
     */
    @SuppressWarnings("unchecked")
    public static <T extends SingletonContextFactory> T getService(Class<T> cls) {
        if (cls == null) {
            log.warn("查询工厂类型参数不可为null");
            return null;
        }
        return (T) MAP.get(cls);
    }

    public static <T> T getBean(Class<T> beanClass) {
        if (beanClass == null) {
            log.warn("查询工厂类型参数不可为null");
            return null;
        }
        BeanContext beanContext = Assert.notNull(getService(BeanContext.class), "Bean容器未注入");
        return beanContext.getBean(beanClass);
    }

    /**
     * 销毁所有工厂实例
     * <p>按初始化顺序的逆序执行销毁</p>
     */
    public static void destroy() {
        if (CollUtil.isEmpty(MAP)) {
            return;
        }

        // 按order值倒序销毁
        Comparator<SingletonContextFactory> comparator = Comparator.comparingInt(SingletonContextFactory::order);
        MAP.values().stream()
                .sorted(comparator.reversed())
                .forEach(factory -> {
                    try {
                        log.debug("正在销毁工厂: {}", factory.getClass().getName());
                        factory.destroy();
                    } catch (Exception e) {
                        log.error("工厂[{}]销毁异常: {}", factory.getClass().getName(), e.getMessage());
                    }
                });
        MAP.clear();
        isLoaded = false;
        log.info("上下文容器已销毁，共清理{}个工厂", MAP.size());
    }
}